package com.xqiapp.xframe.plugin.codes.support;

import java.io.File;
import java.io.FileFilter;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 处理添加类的模板操作
 * 
 * @author mike
 * @date 2016年7月13日
 * @version 0.0.1
 */
public abstract class ClassTemplate {

	private static final Logger LOG = LoggerFactory.getLogger(ClassTemplate.class);

	protected final String pkg;

	protected ClassTemplate(String pkg) {
		this.pkg = pkg;
	}

	/**
	 * 返回所有指定包下面的class
	 * 
	 * @return list
	 */
	public final List<Class<?>> getClassList() {
		List<Class<?>> classList = new ArrayList<Class<?>>();
		try {
			Enumeration<URL> urls = ClassSupport.getClassLoader().getResources(pkg.replace(".", "/"));
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				if (null != url) {
					// 获取协议名称 ，分为file 和 jar
					String protocol = url.getProtocol();
					if ("file".equals(protocol)) {
						String pckgPath = url.getPath().replaceAll("%20", " ");
						addClass(classList, pckgPath, pkg);
					} else if ("jar".equals(protocol)) {
						JarURLConnection jarUrlConnection = (JarURLConnection) url.openConnection();
						JarFile jarFile = jarUrlConnection.getJarFile();
						Enumeration<JarEntry> jarEntries = jarFile.entries();
						while (jarEntries.hasMoreElements()) {
							JarEntry jarEntry = jarEntries.nextElement();
							String jarEntryName = jarEntry.getName();
							if (jarEntryName.endsWith(".class")) {
								String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
								doAddClass(classList, className);
							}
						}
					}
				}
			}
		} catch (Exception e) {
			LOG.error("Auto test load class error", e);
		}
		return classList;
	}

	/**
	 * 添加class的逻辑处理
	 * 
	 * @param clsList
	 * @param pckgPath
	 * @param pckgName
	 */
	public void addClass(List<Class<?>> clsList, String pckgPath, String pckgName) {
		File[] files = new File(pckgPath).listFiles(new FileFilter() {
			public boolean accept(File file) {
				return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
			}
		});
		for (File file : files) {
			String fileName = file.getName();
			if (file.isFile()) {
				String className = fileName.substring(0, fileName.lastIndexOf("."));
				if (!"".equals(pckgName) && null != pckgName) {
					className = pckgName + "." + className;
				}
				doAddClass(clsList, className);
			} else {
				// 当是文件夹的时候，获取子包
				String subPckgPath = fileName;
				if (!"".equals(pckgPath) && null != pckgPath) {
					subPckgPath = pckgPath + "/" + subPckgPath;
				}
				// 获取子包名
				String subPckgName = fileName;
				if (!"".equals(pckgName) && null != pckgName) {
					subPckgName = pckgName + "." + subPckgName;
				}
				// 递归调用
				addClass(clsList, subPckgPath, subPckgName);
			}
		}
	}

	/**
	 * 执行class添加操作
	 * 
	 * @param clsList
	 * @param className
	 */
	public void doAddClass(List<Class<?>> clsList, String className) {
		Class<?> cls = ClassSupport.loadClass(className, false);
		// 判断是否可以添加类
		if (checkAddClass(cls)) {
			clsList.add(cls);
		}
	}

	/**
	 * 用于检查是否允许添加这个类
	 * 
	 * @param cls
	 * @return
	 */
	public abstract boolean checkAddClass(Class<?> cls);

}
